package cn.jimmie.learn.viewArt.captcha.internal;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import cn.jimmie.learn.viewArt.R;

/**
 * FUCTION :
 * Created by jimmie.qian on 2018/12/10.
 */
public class TextSeekBar extends View {
    private static final int NONE = 0;
    private static final int MOVE = 1;
    private static final int FAIL = 2;

    private final int OFFSET;

    private Paint mPaintShadow = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

    private Bitmap mThumb;
    private Bitmap mThumbShadow;
    private Bitmap mThumbStart;
    private Bitmap mThumbFail;

    private String mText;

    private int mProgressColor;
    private int mProgressFailColor;
    private int mIndeterminateColor;
    private int mTextColor;
    private int mProgress = 0;
    private int mIndeterminateRadius;
    private int mThumbRadius;
    private int mWidth;
    private int mHeight;
    private boolean mTouchable = true;

    private int mState = NONE;

    private OnSeekBarChangeListener mListener;
    private ValueAnimator mAnimator = ValueAnimator.ofInt();

    private float mRatio = 1;

    // =============== public method =====================

    public void setListener(OnSeekBarChangeListener listener) {
        mListener = listener;
    }

    public void resetWithAnimator(int target) {
        mAnimator.cancel();
        mAnimator.setIntValues(mProgress, target);
        mAnimator.start();
    }

    public void reset(int target) {
        mAnimator.cancel();
        setProgress(target);
    }

    public void setProgress(int progress) {
        mProgress = (int) ((float) progress / mRatio);
        invalidate();
    }

    public void setMax(int max) {
        mRatio = (float) max / (float) (mWidth - mHeight);
    }

    @SuppressWarnings("unused")
    public void setTouchable(boolean touchable) {
        mTouchable = touchable;
    }

    public interface OnSeekBarChangeListener {

        void onProgressChanged(int progress);

        void onStartTouch();

        void onStopTouch();
    }


    public TextSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TextSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        float dipUnit = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        OFFSET = (int) (dipUnit * 3);

//        int[] attrsArray = new int[]{android.R.attr.layout_width, android.R.attr.layout_height};
//        TypedArray sta = context.obtainStyledAttributes(attrs, attrsArray);
//        mWidth = sta.getDimensionPixelSize(0, ViewGroup.LayoutParams.MATCH_PARENT);
//        mHeight = sta.getDimensionPixelSize(1, ViewGroup.LayoutParams.MATCH_PARENT);
//        sta.recycle();

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TextSeekBar);
        mWidth = ta.getDimensionPixelOffset(R.styleable.SeekCaptchaView_android_layout_width, ViewGroup.LayoutParams.MATCH_PARENT);
        mHeight = ta.getDimensionPixelOffset(R.styleable.TextSeekBar_android_layout_height, ViewGroup.LayoutParams.MATCH_PARENT);
        mProgressColor = ta.getColor(R.styleable.TextSeekBar_progressColor, Color.RED);
        mProgressFailColor = ta.getColor(R.styleable.TextSeekBar_progressFailColor, Color.RED);
        mIndeterminateColor = ta.getColor(R.styleable.TextSeekBar_indeterminateColor, Color.GRAY);
        mTextColor = ta.getColor(R.styleable.TextSeekBar_textColor, Color.BLACK);
        mIndeterminateRadius = ta.getDimensionPixelOffset(R.styleable.TextSeekBar_indeterminateRadius, mHeight / 3);
        mThumbRadius = mHeight / 2 - OFFSET;

        Drawable thumbDrawable = ta.getDrawable(R.styleable.TextSeekBar_thumb);
        //noinspection ConstantConditions
        mThumb = drawableToBitmap(thumbDrawable, mThumbRadius * 2, mThumbRadius * 2);
        Drawable thumbStartDrawable = ta.getDrawable(R.styleable.TextSeekBar_thumbStart);
        if (thumbStartDrawable == null) mThumbStart = mThumb;
        else mThumbStart = drawableToBitmap(thumbStartDrawable, mThumbRadius * 2, mThumbRadius * 2);
        Drawable thumbFailDrawable = ta.getDrawable(R.styleable.TextSeekBar_thumbFail);
        if (thumbFailDrawable == null) mThumbFail = mThumb;
        else mThumbFail = drawableToBitmap(thumbFailDrawable, mThumbRadius * 2, mThumbRadius * 2);

        mThumbShadow = mThumb.extractAlpha();
        mText = ta.getString(R.styleable.TextSeekBar_text);
        ta.recycle();

        mWidth -= OFFSET * 2;

        mPaint.setStrokeWidth(mIndeterminateRadius * 2);
        mPaint.setTextSize((float) (mIndeterminateRadius * 1.5));
        mPaint.setTextAlign(Paint.Align.CENTER);

        mPaintShadow.setMaskFilter(new BlurMaskFilter(OFFSET, BlurMaskFilter.Blur.SOLID));
        mPaintShadow.setColor(Color.BLACK);

        // 关闭硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mState = FAIL;
                mProgress = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mState = NONE;
            }

            @Override
            public void onAnimationStart(Animator animation) {
                mState = FAIL;
            }
        });
        mAnimator.setDuration(300);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        int mid = getHeight() / 2;

        canvas.save();
        canvas.translate(OFFSET, 0);

        // 进度条 左半边进度条
        if (mState == FAIL) mPaint.setColor(mProgressFailColor);
        else mPaint.setColor(mProgressColor);
        canvas.drawCircle(mThumbRadius, mid, mIndeterminateRadius, mPaint);
        canvas.drawLine(mThumbRadius, mid, mThumbRadius + mProgress, mid, mPaint);
        // 进度条右半边
        mPaint.setColor(mIndeterminateColor);
        canvas.drawLine(mThumbRadius + mProgress, mid, mWidth - mThumbRadius, mid, mPaint);
        canvas.drawCircle(mWidth - mThumbRadius, mid, mIndeterminateRadius, mPaint);

        // 在中间绘制 文字
        mPaint.setColor(mTextColor);
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        float top = fontMetrics.top;
        float bottom = fontMetrics.bottom;
        int baseLineY = (int) (getHeight() / 2 - top / 2 - bottom / 2);
        canvas.drawText(mText, mWidth / 2, baseLineY, mPaint);

        // 绘制滑块
        Bitmap bitmap = mThumb;
        if (mState == MOVE) bitmap = mThumbStart;
        else if (mState == FAIL) bitmap = mThumbFail;
        canvas.drawBitmap(mThumbShadow, mProgress, mid - mThumbRadius, mPaintShadow);
        canvas.drawBitmap(bitmap, mProgress, mid - mThumbRadius, null);

        canvas.restore();
    }

    private static Bitmap drawableToBitmap(Drawable drawable, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        drawable.setBounds(0, 0, width, height);
        Canvas canvas = new Canvas(bitmap);
        drawable.draw(canvas);
        return bitmap;
    }

    private boolean shouldMove = false;

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent event) {
        if (!mTouchable) return false;
        int x = (int) event.getX();
        int y = (int) event.getY();
        int width = getWidth();
        int midHeight = getHeight() / 2;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 判断是否在范围内
                if (x > mProgress + OFFSET && x < mProgress + 2 * mThumbRadius + OFFSET && y > midHeight - mThumbRadius && y < midHeight + mThumbRadius) {
                    shouldMove = true;
                    mState = MOVE;
                    if (mListener != null) mListener.onStartTouch();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (!shouldMove || x < mThumbRadius + OFFSET || x > width - mThumbRadius - OFFSET)
                    break;
                mProgress = x - mThumbRadius - OFFSET;
                if (mListener != null)
                    mListener.onProgressChanged((int) ((float) mProgress * mRatio));
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                if (shouldMove && mListener != null) mListener.onStopTouch();
                shouldMove = false;
                mState = NONE;
                break;
        }
        return true;
    }

    @Override
    protected void onDetachedFromWindow() {
        mAnimator.cancel();
        super.onDetachedFromWindow();
    }
}
